using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace NMollom.Internal {
    /// <summary>
    /// The authentication class encapsulates the Mollom authentication scheme.
    /// Provided with a public and private key, it can automatically calculate the 
    /// needed extra authentication parameters.
    /// </summary>
    public class Authentication {
        private readonly string publicKey;
        private readonly string privateKey;
        private string nonce;
        private string time;
        private string hash;

        /// <summary>
        /// Initializes a new instance of the <see cref="Authentication"/> class.
        /// </summary>
        /// <param name="publicKey">The public key.</param>
        /// <param name="privateKey">The private key.</param>
        public Authentication(string publicKey, string privateKey) {
            this.publicKey = publicKey;
            this.privateKey = privateKey;
            Reset();
        }

        /// <summary>
        /// Gets the public key.
        /// </summary>
        /// <value>A string containing the public key.</value>
        public string PublicKey {
            get { return publicKey; }
        }

        /// <summary>
        /// Gets the private key.
        /// </summary>
        /// <value>A string containing the private key.</value>
        public string PrivateKey {
            get { return privateKey; }
        }

        /// <summary>
        /// Gets the calculated nonce value.
        /// </summary>
        /// <value>A string representing the nonce value.</value>
        public string Nonce {
            get { return nonce; }
        }

        /// <summary>
        /// Gets the calculated time value, in the proper format.
        /// </summary>
        /// <value>A string representing the time value.</value>
        public string Time {
            get { return time; }
        }

        /// <summary>
        /// Gets the calculated hash value.
        /// </summary>
        /// <value>A string representing the hash value.</value>
        public string Hash {
            get { return hash; }
        }

        /// <summary>
        /// Calculates a new authentication key (based on the current time).
        /// The public and private keys are reused.
        /// </summary>
        /// <returns>A new authenication object.</returns>
        public Authentication Next() {
            return new Authentication(publicKey, privateKey);
        }

        /// <summary>
        /// Recalculates the time dependent values (nonce, time, hash).
        /// </summary>
        public void Reset() {
            time = DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss.fff") + DateTime.Now.ToString("zzz").Replace(":", "");
            nonce = Guid.NewGuid().ToString("N");

            // calc hash
            HMAC hmac = new HMACSHA1(Encoding.UTF8.GetBytes(privateKey));
            byte[] hashed = hmac.ComputeHash(Encoding.UTF8.GetBytes(string.Concat(time, ":", nonce, ":", privateKey)));
            hash = Convert.ToBase64String(hashed);
        }
    }
}